<?php

namespace App\Services\Third;

use App\Constant\CacheConst;
use App\Constant\Constant;
use App\Constant\TimeConst;
use App\Exceptions\ExceptionHelper;
use App\Exceptions\ExceptionSms;
use App\Format\BaseFormat;
use App\Http\Request;
use App\Services\Common\ConfigService;
use Carbon\Carbon;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use QiNiu;
use \Log as Log;

/**
 * error code 说明.
 * <ul>
 *    <li>-41001: encodingAesKey 非法</li>
 *    <li>-41003: aes 解密失败</li>
 *    <li>-41004: 解密后得到的buffer非法</li>
 *    <li>-41005: base64加密失败</li>
 *    <li>-41016: base64解密失败</li>
 * </ul>
 */
class Wechat extends Base
{
    public static $OK                = 0;
    public static $IllegalAesKey     = -41001;
    public static $IllegalIv         = -41002;
    public static $IllegalBuffer     = -41003;
    public static $DecodeBase64Error = -41004;

    private $isMini;

    const MsgType_Text            = 'text'; // 文本消息
    const MsgType_Image           = 'image'; // 图片消息
    const MsgType_Link            = 'link'; // 图文链接
    const MsgType_MiniProgramPage = 'miniprogrampage'; // 小程序卡片

    private $host = 'https://api.weixin.qq.com';
    private $port = 80;
    private $appId;
    private $appSecret;
    const WechatAuth            = '/sns/jscode2session';
    const WechatGetPhone        = '/wxa/business/getuserphonenumber';
    const WechatAccessToken     = '/cgi-bin/token';
    const WechatUpTempMedia     = '/cgi-bin/media/upload';
    const WechatSendCustomMsg   = '/cgi-bin/message/custom/send';
    const WechatSendTemplateMsg = '/cgi-bin/message/template/send';
    const WechatUserInfo        = '/cgi-bin/user/info';

    const ORDER_PAY_SUCCESS = '8-8RKtyBx9Sg3AaPNV_ViGPjC6TAmO-mCW5xWBhBRns'; // 订单支付成功通知
    /**
     * @var string[]
     */
    public static $errorCodeMap = [
        40029 => 'code无效',
        45011 => '频率限制，每个用户每分钟100次',
        -1    => '系统繁忙，此时稍候再试',
//        40001 => 'AppSecret 错误或者 AppSecret 不属于这个小程序，请开发者确认 AppSecret 的正确性',
//        40002 => '请确保 grant_type 字段值为 client_credential',
        40013 => '不合法的 AppID，请开发者检查 AppID 的正确性，避免异常字符，注意大小写',
        40004 => '无效媒体文件类型',
        40001 => '获取 access_token 时 AppSecret 错误，或者 access_token 无效。请开发者认真比对 AppSecret 的正确性，或查看是否正在为恰当的小程序调用接口',
        40002 => '不合法的凭证类型',
        40003 => '不合法的 OpenID，请开发者确认 OpenID 是否是其他小程序的 OpenID',
        45015 => '回复时间超过限制',
        45047 => '客服接口下行条数超过上限',
        48001 => 'API 功能未授权，请确认小程序已获得该接口',
    ];

    public static function getErrorMsg($code)
    {
        return self::$errorCodeMap[$code] ?? "";
    }

    public function __construct($appId, $appSecret, $isMini = true)
    {
        $this->appId     = $appId;
        $this->appSecret = $appSecret;
        $host            = $this->host;
        $port            = $this->port;
        $this->isMini    = $isMini;
        parent::__construct($host, $port);
    }

    /**
     * 获取用户授权信息
     * @param $code
     * @return array
     * @throws \Throwable
     * @name:getUserAuthInfo
     * @author: lisa
     * @datetime: 2021/10/13 9:02
     */
    public function getUserAuthInfo($code)
    {
        $params = [
            'appid'      => $this->appId,
            'secret'     => $this->appSecret,
            'js_code'    => $code,
            'grant_type' => 'authorization_code'
        ];
        \Log::info("微信用户授权请求参数：" . json_encode($params));
        $result     = $this->request(self::WechatAuth, $params);
        $error_code = $result['errcode'] ?? 0;
        $msg        = self::getErrorMsg($error_code);
        \Log::info("获取微信用户授权信息：" . json_encode($result, JSON_UNESCAPED_UNICODE));
        if ($error_code == 0) {
            return [
                'openid'      => $result['openid'],
                'session_key' => $result['session_key'],
                'unionid'     => $result['unionid'] ?? "",
            ];
        } else {
            ExceptionSms::returnError($msg);
        }
    }

    public function getPhone($code)
    {
        $params       = [
            'code' => $code,
        ];
        $access_token = self::getAccessToken();
        \Log::info("微信用户手机号：" . json_encode($params));
        $result     = $this->request(self::WechatGetPhone . "?access_token=" . $access_token, $params, 'POST', true);
        $error_code = $result['errcode'] ?? 0;
        $msg        = self::getErrorMsg($error_code);
        \Log::info("获取微信用户授权信息：" . json_encode($result, JSON_UNESCAPED_UNICODE));
        if ($error_code == 0) {
            return $result['phone_info']['phoneNumber'] ?? "";
        } else {
            ExceptionSms::returnError($msg);
        }
    }

    /**
     * 检验数据的真实性，并且获取解密后的明文.
     * @param $sessionKey string 用户在小程序登录后获取的会话密钥
     * @param $encryptedData string 加密的用户数据
     * @param $iv string 与用户数据一同返回的初始向量
     * @name:decryptData
     * @author: lisa
     * @datetime: 2021/11/7 20:19
     */
    public function decryptData($sessionKey, $encryptedData, $iv)
    {
        if (strlen($sessionKey) != 24) ExceptionSms::returnError('sessionKey 非法');
        $aesKey = base64_decode($sessionKey);
        if (strlen($iv) != 24) ExceptionSms::returnError('iv 非法');
        $aesIV     = base64_decode($iv);
        $aesCipher = base64_decode($encryptedData);
        $result    = openssl_decrypt($aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);
        \Log::info("微信用户解析信息：" . $result);
        return json_decode($result, true);
    }

    /**
     * 解密微信用户信息
     * @param $sessionKey
     * @param $iv
     * @param $encryptedData
     * @return mixed
     * @name:decryptUserInfo
     * @deprecated
     * @author: lisa
     * @datetime: 2021/10/13 9:12
     */
    public function decryptUserInfo($sessionKey, $iv, $encryptedData)
    {
        \Log::info("sessionKey=" . $sessionKey);
        \Log::info("iv=" . $iv);
        \Log::info("encryptedData=" . $encryptedData);
        // 解密微信用户信息
        $key = base64_decode($sessionKey);
        $iv  = base64_decode($iv);
        $d   = base64_decode($encryptedData);

        $data = openssl_decrypt($d, 'AES-128-CBC', $key, 1, $iv);
        \Log::info("解密微信用户信息：" . $data);

        return json_decode($data, true);
    }

    /**
     * 获取微信access_token
     * @return mixed
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \Throwable
     * @name:getAccessToken
     * @author: lisa
     * @datetime: 2021/11/19 14:15
     */
    public function getAccessToken()
    {
        $token = Cache::get('wechat_access_token');
        if ($token) return $token;
        $params     = [
            'appid'      => $this->appId,
            'secret'     => $this->appSecret,
            'grant_type' => 'client_credential'
        ];
        $result     = $this->request(self::WechatAccessToken, $params);
        $error_code = $result['errcode'] ?? 0;
        $msg        = self::getErrorMsg($error_code);
        if ($error_code == 0) {
            $data = [
                'access_token' => $result['access_token'],
                'expires_in'   => $result['expires_in'],
            ];
            Cache::set('wechat_access_token', $data['access_token'], ceil($data['expires_in'] / 64));
            return $data['access_token'];
        } else {
            ExceptionSms::returnError($error_code . $msg);
        }
    }

    /**
     * @param $openid
     * @return array|mixed|void
     * @throws \Throwable
     * @name: getWechatUserInfo
     * @Author: caoJunWei
     * @Datetime: 2022/1/19 18:48
     */
    public function getWechatUserInfo($openid)
    {
        $token = Cache::get('wechat_access_token');
        if (!$token) $token = $this->getAccessToken();
        $params     = [
            'access_token' => $token,
            'openid'       => $openid,

        ];
        $result     = $this->request(self::WechatUserInfo, $params);
        $error_code = $result['errcode'] ?? 0;
        $msg        = self::getErrorMsg($error_code);
        if ($error_code == 0) {
            return [
                'openid'      => $result['openid'] ?? '',
                'session_key' => $result['session_key'] ?? '',
                'unionid'     => $result['unionid'] ?? '',
            ];
        } else {
            ExceptionSms::returnError($msg);
        }
    }

    /**
     * 发送消息
     * @param $touser string  用户的 OpenID
     * @param $content
     * @return array
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \Throwable
     * @name:sendImageMessage
     * @author: lisa
     * @datetime: 2021/11/19 14:26
     */
    public function sendImageMessage($touser, $content)
    {
        $params     = [
            'touser'  => $touser, // 用户的 OpenID
            'msgtype' => self::MsgType_Image, // 消息类型
            'image'   => [
                'media_id' => $content
            ], // 图片消息，msgtype="image" 时必填
        ];
        $uri        = self::WechatSendCustomMsg . "?access_token={$this->getAccessToken()}";
        $result     = $this->request($uri, $params, Request::POST_METHOD, true);
        $error_code = $result['errcode'] ?? 0;
        $msg        = self::getErrorMsg($error_code);
        if ($error_code == 0) {
            return [
                'openid'      => $result['openid'],
                'session_key' => $result['session_key'],
            ];
        } else {
            ExceptionSms::returnError($msg);
        }
    }

    /**
     * 存储微信头像
     * @param $url
     * @return array|false|string|string[]
     * @throws \Exception
     * @author: lisa
     * @datetime: 2021/10/13 9:13
     */
    public static function storeWechatAvatar($url)
    {
        if ($url) {
            $newFileName = Str::random(40) . '.jpg';
            $save        = Storage::disk('image')->put($newFileName, self::httpGetData($url));
            $url         = Storage::disk('image')->url($newFileName);
            return $url;
        } else {
            return false;
        }
    }

    /**
     * 获取文件后缀
     * @param $url
     * @return false|string
     * @name:getExtension
     * @author: lisa
     * @datetime: 2021/10/13 9:13
     */
    public static function getExtension($url)
    {
        // mime 和 扩展名 的映射
        $mimes   = array(
            'image/bmp'    => 'bmp',
            'image/gif'    => 'gif',
            'image/jpeg'   => 'jpg',
            'image/png'    => 'png',
            'image/x-icon' => 'ico'
        );
        $headers = get_headers($url, 1);
        if (!isset($mimes[$headers['Content-Type']])) {
            return false;
        }
        return $mimes[$headers['Content-Type']];
    }

    /**
     * 获取文件内容
     * @param $url
     * @return false|string
     * @name:httpGetData
     * @author: lisa
     * @datetime: 2021/10/13 9:14
     */
    public static function httpGetData($url)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_URL, $url);
        ob_start();
        curl_exec($ch);
        $return_content = ob_get_contents();
        ob_end_clean();
        return $return_content;
    }
}
